package com.gaogzhen.designPattern.immutableObject.immutable;

import lombok.extern.slf4j.Slf4j;

import java.sql.Connection;
import java.util.concurrent.atomic.AtomicIntegerArray;

/**
 * 自定义线程连接池
 */
@Slf4j(topic = "c.Pool")
public final class Pool {
    /** 连接池大小 */
    private final int poolSize;
    /** 连接数组 */
    private final Connection[] conns;
    /** 连接是否被占用标记,0-未占用，1-已占用 */
    private final AtomicIntegerArray busies;

    /**
     * 构造方法：初始化连接池
     * @param poolSize      初始连接池大小
     */
    public Pool(int poolSize) {
        this.poolSize = poolSize;
        conns = new Connection[poolSize];
        busies = new AtomicIntegerArray(new int[poolSize]);
        for (int i = 0; i < poolSize; i++) {
            conns[i] = new MockConnection("conn" + i);
        }
    }

    /**
     * 从连接池获取连接
     * @return      连接
     */
    public Connection getConnection() {
        // 检查是否有空闲连接
        while (true) {
            for (int i = 0; i < poolSize; i++) {
                // 有空闲连接返回连接
                if (busies.get(i) == 0) {
                    // 空闲，修改标记，返回连接
                    if (busies.compareAndSet(i, 0, 1)) {
                        log.debug("get {}", conns[i]);
                        return conns[i];
                    }
                }
            }
            // 没有空闲连接等待
            synchronized (this) {
                try {
                    log.debug("wait...");
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 归还连接
     * @param conn      要归还的连接
     */
    public void close(Connection conn) {
        for (int i = 0; i < poolSize; i++) {
            if (conns[i] == conn) {
                // 归还连接不会发生竞争
                busies.set(i, 0);
                synchronized (this) {
                    log.debug("close {}", conn);
                    this.notifyAll();
                }
                break;
            }
        }
    }
}
